package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.feign.schedule.IScheduleClient;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.schedule.dto.Task;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.ProtostuffUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.AutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.thread.UserThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private AutoScanService autoScanService;

    @Autowired
    private IScheduleClient scheduleClient;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        Date beginPubDate = dto.getBeginPubDate();//开始时间
        Date endPubDate = dto.getEndPubDate();//结束时间
        Integer channelId = dto.getChannelId();//所属频道Id
        String keyword = dto.getKeyword();//关键字
        Short status = dto.getStatus();//状态
        Integer currentPage = dto.getPage();//当前页
        Integer size = dto.getSize();

        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();

        //登录用户Id
        queryWrapper.eq(WmNews::getUserId, UserThreadLocal.get().getId());
        queryWrapper.eq(status != null, WmNews::getStatus, status);//状态
        queryWrapper.eq(channelId != null, WmNews::getChannelId, channelId);//所属频道
        queryWrapper.between(beginPubDate != null && endPubDate != null, WmNews::getPublishTime, beginPubDate, endPubDate);//时间范围
        queryWrapper.like(StringUtils.isNotEmpty(keyword), WmNews::getTitle, keyword);//关键字:模糊匹配
        queryWrapper.orderByDesc(WmNews::getPublishTime);//排序
        Page<WmNews> page = new Page<>(currentPage, size);

        page = wmNewsMapper.selectPage(page, queryWrapper);
        Long total = page.getTotal();

        PageResponseResult result = new PageResponseResult(currentPage, size, total.intValue());
        result.setData(page.getRecords());
        return result;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResponseResult submit(WmNewsDto dto) {
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);//参数缺失
        }
        //1.提取新闻内容
        WmNews wmNews = wmNewsDto2WmNews(dto);//调用自定义方法WmNewsDto2WmNews方法转化类型
        //2.插入新闻表
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);//参数缺失
        }
        int insert = wmNewsMapper.insert(wmNews);
        if (insert < 1) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
        }

        //3.判断是否为草稿 是--->直接返回
        if (0 == dto.getStatus()) {
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        Short type = dto.getType();
        String content = dto.getContent();

        //4.获取图文素材信息,插入到素材表中
        List<String> contentImages = getContentImages(content);//获取内容图并插入
        Boolean contentImagesAddBoolean = addWmMaterial(wmNews.getId(), (short) 0, contentImages);
        if (!contentImagesAddBoolean) {
            throw new RuntimeException("内容图添加失败");
        }

        List<String> coverImages = getCoverImages(type, contentImages, dto.getImages());//获取封面图并插入

        //补齐原WmNews中缺少的Type和Images字段
        Boolean aBoolean = updateWmNews(wmNews, coverImages);
        if (!aBoolean) {
            log.warn("Type和Images字段补齐失败");
        }


        Boolean coverImagesAddBoolean = addWmMaterial(wmNews.getId(), (short) 1, coverImages);
        if (!coverImagesAddBoolean) {
            throw new RuntimeException("封面图添加失败");
        }

//        //5.调用阿里云审核
//        try {
//            autoScanService.autoScanWmNews(wmNews.getId());
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

        //5.调用延迟队列添加任务
        Boolean addToTaskResponse = addToTask(wmNews.getId(), dto.getPublishTime().getTime());
        if (!addToTaskResponse) {
            log.warn("延迟队列添加任务失败");
            throw new RuntimeException("延迟队列添加任务失败");
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult downOrUp(WmNewsDto wmNewsDto) {
        //0.入参处理
        if (wmNewsDto == null) {
            log.warn("入参不能为空");
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        Integer id = wmNewsDto.getId();//新闻id
        Short enable = wmNewsDto.getEnable();//上下架

        //1.查询数据库中wmNews表
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            log.warn("新闻不存在");
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "新闻不存在");
        }
        //判断文章是否已发布
        if (9 != wmNews.getStatus()) {
            log.warn("新闻还没有发布");
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        //2.修改上架状态
        wmNews.setEnable(enable);
        int updateResponse = wmNewsMapper.updateById(wmNews);
        if (updateResponse < 1) {
            log.warn("修改新闻上架状态失败");
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "修改新闻上架状态失败");
        }

        //3.向延迟队列发送任务
        Long articleId = wmNews.getArticleId();//3.1.处理发送的参数
        HashMap<String, Object> map = new HashMap<>();
        map.put("articleId", articleId);
        map.put("enable", (enable == 0));//article里面1:true为下架   0false为上架
        String message = JSON.toJSONString(map);//转成json格式
        kafkaTemplate.send("news.up.or.down", message);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    //延迟队列添加任务
    private Boolean addToTask(Integer newsId, Long executeTime) {
        Task task = new Task();
        //task.setTaskId();

        WmNews wmNews = new WmNews();//参数传入对象类型,方便后续扩展
        wmNews.setId(newsId);
        byte[] serialize = ProtostuffUtil.serialize(wmNews);//序列化
        task.setParameters(serialize);

        task.setExecuteTime(executeTime);

        //feign远程调用schedule接口的addTask方法添加任务
        ResponseResult responseResult = scheduleClient.addTask(task);

        return (responseResult != null && responseResult.getCode() == 200);//Boolean
    }

    //这个方法用于补齐原WmNews中缺少的Type和Images字段
    private Boolean updateWmNews(WmNews wmNews, List<String> coverImages) {
        WmNews wmNews1 = new WmNews();
        wmNews1.setId(wmNews.getId());
        int size = coverImages.size();
        if (size > 1) {
            wmNews1.setType((short) 3);
        } else if (size == 1) {
            wmNews1.setType((short) 1);
        } else {
            wmNews1.setType((short) 0);
        }

        wmNews1.setImages(StringUtils.join(coverImages, ","));//设置封面图字段

        int i = wmNewsMapper.updateById(wmNews1);
        return i > 0;
    }

    //这个方法用于向数据表中插入素材和素材关系
    private Boolean addWmMaterial(Integer wmNewsId, Short type, List<String> ImageList) {
        if (!CollectionUtils.isEmpty(ImageList)) {
            for (String contentImage : ImageList) {
                WmMaterial wmMaterial = new WmMaterial();
                wmMaterial.setUserId(UserThreadLocal.get().getId());
                wmMaterial.setUrl(contentImage);
                wmMaterial.setType((short) 0);//0代表图片
                wmMaterial.setIsCollection((short) 0);//0代表未收藏
                wmMaterial.setCreatedTime(new Date());
                int insert1 = wmMaterialMapper.insert(wmMaterial);
                if (insert1 < 1) {
                    throw new RuntimeException("素材添加失败");
                }
                //6.同时插入关系表
                WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
                wmNewsMaterial.setMaterialId(wmMaterial.getId());
                wmNewsMaterial.setNewsId(wmNewsId);
                wmNewsMaterial.setType(type);//内容引用
                wmNewsMaterial.setOrd((short) 1);
                int insert2 = wmNewsMaterialMapper.insert(wmNewsMaterial);
                if (insert2 < 1) {
                    throw new RuntimeException("素材关系添加失败");
                }
            }
        }
        return true;
    }

    //这个方法只为了获取取封面图片
    private List<String> getCoverImages(Short type, List<String> contentImages, List<String> coverImages) {
        if (type == -1) {//自动从内容图中提取封面图
            if (contentImages.size() > 3) {
                return contentImages.subList(0, 3);//大于三张:只拿前三张
            } else {
                return contentImages;//内容图中小于三张图片 直接将封面图拷贝过来即可
            }
        } else {
            return coverImages;//无图/单图/多图
        }
    }

    //获取新闻内容图
    private List<String> getContentImages(String content) {
        if (StringUtils.isEmpty(content)) {
            return new ArrayList<>();
        }
        ArrayList<String> urlList = new ArrayList<>();//结果集
        //将content转为map集合
        List<Map> maps = JSON.parseArray(content, Map.class);
        if (CollectionUtils.isEmpty(maps)) {
            return new ArrayList<>();
        }
        for (Map map : maps) {
            //找到type=image的map数据
            String type = (String) map.get("type");
            if ("image".equals(type)) {
                String url = (String) map.get("value");
                urlList.add(url);
            }
        }
        return urlList;
    }

    //前端传入的WmNewsDto转成WmNews
    private WmNews wmNewsDto2WmNews(WmNewsDto dto) {
        if (dto == null) {
            return null;
        }
        //提取新闻内容,构建WmNews
        WmNews wmNews = new WmNews();
        //自动映射
        BeanUtils.copyProperties(dto, wmNews);
        //额外字段处理
        wmNews.setUserId(UserThreadLocal.get().getId());//用户Id:从UserThreadLocal中提取
        wmNews.setCreatedTime(new Date());//创建时间
        wmNews.setEnable((short) 1);

        List<String> images = dto.getImages();//设置图片: images类型转换
        if (CollectionUtils.isEmpty(images)) {
            String join = StringUtils.join(images, ",");
            wmNews.setImages(join);
        }
        //文章封面类型:自动
        if (dto.getType() == -1) {
            wmNews.setType(null);//自动则将类型设置为null
        }
        return wmNews;
    }
}